package sharemem

/*
#cgo LDFLAGS: -pthread
#include <stdio.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
*/
import "C"
import (
	"log"
	"server_cluster/battle/battle_config"
	"syscall"
	"unsafe"
)

var Myshm *MyData

const (
	BATTLE_GROUP_MAX  = 1000
	BATTLE_MAX        = 1000
	BATTLE_CAPTAIN    = 1000
	BUFF_MAX          = 1000
	MONSTER_MAX       = 1000
	MONSTER_ATTR_MAX  = 2000
	SKILL_MAX         = 1000
	SKILL_CHILD_MAX   = 1000
	SKILL_CARD_MAX    = 1000
	SKILL_EFFECT_MAX  = 2000
	SKILL_CHANT_MAX   = 1000
	SKILL_PASSIVE_MAX = 1000
	CONDITION_MAX     = 1000
)

type Config struct {
	Btgp   [BATTLE_MAX]BattleGroup
	Bt     [BATTLE_MAX]Battle
	Btcpt  [BATTLE_CAPTAIN]BattleCaptain
	Bf     [BUFF_MAX]Buff
	Mst    [MONSTER_MAX]Monster
	Mstat  [MONSTER_ATTR_MAX]MonsterAttr
	Sklcd  [SKILL_CARD_MAX]SkillCard
	Sklchd [SKILL_CHILD_MAX]SkillChild
	Sklef  [SKILL_EFFECT_MAX]SkillEffect
	Sklpas [SKILL_PASSIVE_MAX]SkillPassive
}

type MyData struct {
	Sem_user [battle_config.SHM_USER_MAX]C.sem_t
	Sem_all  C.sem_t //全局唯一锁
	//config
	Cfg Config
	//user
	ShmUser [battle_config.SHM_USER_MAX]ShmUser

	Site_user   int32
	Time_now    int64
	Status      int8 //主进程状态 0初始化 1运行中 2停止新的连接请求 3 停止新的业务请求
	Status_sync int8
	Stock       int32
}

func Init_myshm() {
	var i int32
	init_mysem(&(Myshm.Sem_all))
	for i = 0; i < battle_config.SHM_USER_MAX; i++ {
		init_mysem(&(Myshm.Sem_user[i]))
	}
	//config
	for i = 0; i < BATTLE_GROUP_MAX; i++ {
		Myshm.Cfg.Btgp[i].meminit()
	}
	for i = 0; i < BATTLE_MAX; i++ {
		Myshm.Cfg.Bt[i].meminit()
	}
	for i = 0; i < BATTLE_CAPTAIN; i++ {
		Myshm.Cfg.Btcpt[i].meminit()
	}
	for i = 0; i < BUFF_MAX; i++ {
		Myshm.Cfg.Bf[i].meminit()
	}
	for i = 0; i < MONSTER_MAX; i++ {
		Myshm.Cfg.Mst[i].meminit()
	}
	for i = 0; i < MONSTER_ATTR_MAX; i++ {
		Myshm.Cfg.Mstat[i].meminit()
	}
	for i = 0; i < SKILL_CARD_MAX; i++ {
		Myshm.Cfg.Sklcd[i].meminit()
	}
	for i = 0; i < SKILL_PASSIVE_MAX; i++ {
		Myshm.Cfg.Sklpas[i].meminit()
	}
	for i = 0; i < SKILL_EFFECT_MAX; i++ {
		Myshm.Cfg.Sklef[i].meminit()
	}
	//user
	for i = 0; i < battle_config.SHM_USER_MAX; i++ {
		Myshm.ShmUser[i].Meminit(i)
	}
	//system
	Myshm.Site_user = 0
	Myshm.Time_now = 0
	Myshm.Status = 0
	Myshm.Status_sync = 0
	Myshm.Stock = battle_config.SHM_USER_MAX
}

func init_mysem(sem *C.sem_t) {
	C.sem_init(sem, 1, 1)
}

func Sem_wait(sem *C.sem_t) {
	C.sem_wait(sem)
}

func Sem_post(sem *C.sem_t) {
	C.sem_post(sem)
}

func Get_myshm(myshm **MyData) uintptr {
	pn := C.CString("/")
	key := C.ftok(pn, (C.int)(battle_config.CONF.SHMKEY))
	C.free(unsafe.Pointer(pn))
	var tmp MyData
	shmsize := unsafe.Sizeof(tmp)
	shmid, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(key), shmsize, 01000|0640)
	if err != 0 {
		log.Println("shmget error:", err.Error())
		return 0
	}
	var sharemem uintptr
	sharemem, _, err = syscall.Syscall(syscall.SYS_SHMAT, shmid, 0, 0)
	*myshm = (*MyData)(unsafe.Pointer(sharemem))
	return shmid
}

func Drop_myshm(shmid uintptr) {
	syscall.Syscall(syscall.SYS_SHMCTL, shmid, 0, 0)
}

func GetTimeNow() int64 {
	return Myshm.Time_now
}

func Get_user_by_id(uid int64, fd int32) *ShmUser {
	//按出入栈规则加解锁 epoll单协程模式免全局锁
	//Sem_wait(&(Myshm.Sem_all))
	v, ok := GetShmUserMap()[uid]
	if ok {
		//Sem_post(&(Myshm.Sem_all))
		return v
	}
	site := Myshm.Site_user
	for i := 0; i < battle_config.SHM_USER_MAX; i++ {
		if site < 0 || site >= battle_config.SHM_USER_MAX {
			site = 0
		}
		if Myshm.ShmUser[site].IsUse() {
			site++
			continue
		}
		//
		Sem_wait(&(Myshm.Sem_user[site]))

		if Myshm.ShmUser[site].IsUse() {
			Sem_post(&(Myshm.Sem_user[site]))
			site++
			continue
		}

		Myshm.ShmUser[site].use(uid)
		Myshm.ShmUser[site].fd = fd
		Myshm.ShmUser[site].kill_time = Myshm.Time_now + battle_config.FIGHT_TIME_MAX
		//初始化保存索引
		SetShmUserMap(uid, &(Myshm.ShmUser[site]))
		//游标滑动
		Myshm.Site_user = site + 1
		if Myshm.Site_user < 0 || Myshm.Site_user >= battle_config.SHM_USER_MAX {
			Myshm.Site_user = 0
		}
		Myshm.Stock--
		Sem_post(&(Myshm.Sem_user[site]))
		//Sem_post(&(Myshm.Sem_all))
		return &(Myshm.ShmUser[site])
		//
	}
	//Sem_post(&(Myshm.Sem_all))
	//服务器爆满
	return nil

}

func Get_user_by_index(index int32) *ShmUser {
	if index < 0 || index >= battle_config.SHM_USER_MAX {
		return nil
	}
	if !Myshm.ShmUser[index].IsUse() {
		return nil
	}
	return &(Myshm.ShmUser[index])
}

func Build_condition_slice(cond [BATTLE_PARAM_MAX1][BATTLE_PARAM_MAX2]int32) [][]int32 {
	var i, j int8
	slice := make([][]int32, 0)
	for i = 0; i < BATTLE_PARAM_MAX1; i++ {
		tmp := make([]int32, 0)
		for j = 0; j < BATTLE_PARAM_MAX2; j++ {
			if cond[i][j] <= 0 && j == 0 {
				break
			}
			tmp = append(tmp, cond[i][j])
		}
		if len(tmp) <= 0 {
			continue
		}
		slice = append(slice, tmp)
	}
	return slice
}
